using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEditor;
using UnityEditor.AddressableAssets.Settings;
using UnityEngine;

/// <summary>
/// 检测类型
/// </summary>
public enum RenameCheckType
{
    Global,
    Addressable
}

/// <summary>
/// 文件重名检索工具
/// </summary>
[InlineEditor]
public class FileRenameCheckTool : BearScriptableObject
{
    [InfoBox("用于指定路径资源检索资源命名重复问题")]
    public RenameCheckType type;
    
    [FolderPath, ShowIf("isGlobal")]
    public List<string> searchPaths = new List<string>();
    
    [TableList, HideLabel, HideIf("isGlobal")] 
    public Dictionary<string, List<AddressableAssetEntry>> records = new Dictionary<string, List<AddressableAssetEntry>>();

    [TableList, HideLabel, ShowIf("isGlobal")] 
    public List<RenameData> records2 = new List<RenameData>();
    
    private bool isGlobal()
    {
        return type != RenameCheckType.Addressable;
    }

    /// <summary>
    ///  group 重复内容
    /// </summary>
    Dictionary<string, List<AddressableAssetEntry>> duplicateContent = new Dictionary<string, List<AddressableAssetEntry>>();

    /// <summary>
    /// 固定生成路径
    /// </summary>
    public override string DefaultPath
    {
        get => "Assets/FileRenameCheck.asset";
    }
    
    /// <summary>
    /// 单例对象，快速获取
    /// </summary>
    private static FileRenameCheckTool _instance;
    public static FileRenameCheckTool Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = Init();
            }

            return _instance;
        }
    }

    // 用于Tools 手动创建对象，前期测试使用
    [MenuItem("Tools/BearTool/File Rename Check")]
    private static void menuOption()
    {
        generate<FileRenameCheckTool>();
    }

    /// <summary>
    /// 初始化，新工具可以按照这个模板来重新写
    /// </summary>
    /// <returns></returns>
    public static FileRenameCheckTool Init()
    {
        var instance = ScriptableObject.CreateInstance<FileRenameCheckTool>();
        instance = AssetDatabase.LoadAssetAtPath<FileRenameCheckTool>(instance.DefaultPath);
        if (instance == null)
        {
            FileRenameCheckTool.menuOption();
            instance = AssetDatabase.LoadAssetAtPath<FileRenameCheckTool>(instance.DefaultPath);
        }

        FileRenameCheckTool._instance = instance;

        return instance;
    }

    [Button("测试文件名称检索", ButtonSizes.Large)]
    private void ForTest()
    {
        switch (type)
        {
            case RenameCheckType.Addressable:
                CheckAASameNameTool();
                break;
            case RenameCheckType.Global:
                CheckFileNameGlobal();
                break;
            default:
                break;
        }
    }

    /// <summary>
    /// 检索 Addressabels 重命名资源工具
    /// 存在重名对象返回 false
    /// </summary>
    public bool CheckAASameNameTool()
    {
        if(duplicateContent == null)
            duplicateContent = new Dictionary<string, List<AddressableAssetEntry>>();
        
        duplicateContent.Clear();
        List<AddressableAssetEntry> enterAddress = new List<AddressableAssetEntry>();
        
        var setting = AAManagementUtils.GetSettings();
        var groups = setting.groups;

        foreach (var group in groups)
        {
            var entries = group.entries.ToArray();
            for (int i = 0; i < entries.Length; i++)
            {
                var enter = entries[i];
                var finded = enterAddress.Find(e => e.address == enter.address);
                var hasSameName =  finded!= null;
                var recorded = duplicateContent.ContainsKey(enter.address);
                if (!hasSameName)
                {
                    enterAddress.Add(enter);
                }
                else
                {
                    if (!recorded)
                    {
                        List<AddressableAssetEntry> es = new List<AddressableAssetEntry>();
                        es.Add(enter);
                        es.Add(finded);
                        duplicateContent.Add(enter.address, es);
                    }
                    else
                    {
                        duplicateContent[enter.address].Add(enter);
                    }
                }
            }
        }

        records = duplicateContent;
        if (duplicateContent.Count > 0)
            return false;

        return true;
    }

    /// <summary>
    /// 全局检索 Addressabels 重命名资源工具
    /// </summary>
    public void CheckFileNameGlobal()
    {
        if (records2 == null)
            records2 = new List<RenameData>();
        records2.Clear();
        
        // fileNames
        Dictionary<string, string> close = new Dictionary<string, string>();
        
        foreach (var path in searchPaths)
        {
            var files = Directory.GetFiles(path.RelaToFullPath(), "*.*", SearchOption.AllDirectories)
                .Where(file => !Path.GetExtension(file).Equals(".meta"));

            foreach (var file in files)
            {
                var p = file.FullPathToRela();
                var name = Path.GetFileNameWithoutExtension(p);
                if (close.ContainsKey(name))
                {
                    var r = records2.Find(data => data.name.Equals(name));
                    if (r == null)
                    {
                        var data = new RenameData(name);
                        data.asset = new List<Object>();
                        records2.Add(data);
                        r = data;
                        
                        r.asset.Add(AssetDatabase.LoadAssetAtPath<Object>(close[name]));
                    }
                    
                    r.asset.Add(AssetDatabase.LoadAssetAtPath<Object>(p));
                }
                else
                {
                    close.Add(name, p);
                }
            }
        }
    }
}

/// <summary>
/// 数据类
/// </summary>
[SerializeField]
public class RenameData
{
    public string name;
    public List<Object> asset;

    public RenameData(string name)
    {
        this.name = name;
    }
}
